package com.minglead.springboot.common.config.webxmladapter;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

import javax.annotation.Priority;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;

import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
/*import org.apache.shiro.cache.ehcache.EhCacheManager;*/
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.ImportResource;
import org.springframework.core.annotation.Order;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import com.alibaba.druid.util.StringUtils;
import com.minglead.springboot.common.config.Global;
import com.minglead.springboot.common.config.webxmladapter.servlet.ValidateCodeServlet;
import com.minglead.springboot.common.security.shiro.session.CacheSessionDAO;
import com.minglead.springboot.common.security.shiro.session.SessionDAO;
import com.minglead.springboot.common.security.shiro.session.SessionManager;
import com.minglead.springboot.common.utils.IdGen;
import com.minglead.springboot.common.utils.SpringContextHolder;
import com.minglead.springboot.platform.sys.listener.WebContextListener;
import com.minglead.springboot.platform.sys.security.CustomCredentialsMatcher;
import com.minglead.springboot.platform.sys.security.SystemAuthorizingRealm;

/**
 * shiro 相关配置
 * @author clz
 * 2018年5月16日
 */
@Configuration
public class ShiroConfiguration {
	
    @Bean
    public FilterRegistrationBean<DelegatingFilterProxy> filterRegistrationBean() {
        FilterRegistrationBean<DelegatingFilterProxy> filterRegistration = new FilterRegistrationBean<DelegatingFilterProxy>();
        filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
        //  该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理  
        filterRegistration.addInitParameter("targetFilterLifecycle", "true");
        filterRegistration.setEnabled(true);
        filterRegistration.addUrlPatterns("/*");
        return filterRegistration;
    }
    
    
	@Bean(name="lifecycleBeanPostProcessor")
	public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor(){
		LifecycleBeanPostProcessor lifecycleBeanPostProcessor = new org.apache.shiro.spring.LifecycleBeanPostProcessor();
		return lifecycleBeanPostProcessor;
	}

	/*自动创建代理类，若不添加，Shiro的注解可能不会生效。*/
	/*支持Shiro对Controller的方法级AOP安全控制 begin*/
	@DependsOn({"lifecycleBeanPostProcessor"})
	@Bean
	public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
		org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
		defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
		return defaultAdvisorAutoProxyCreator;
	}
    /**
     * 开启shiro注解
     * @return
     */
	@Bean
	public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(){
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =  new org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor();	
		authorizationAttributeSourceAdvisor.setSecurityManager(getSecurityManager());
		return authorizationAttributeSourceAdvisor;
	}
	

    /**
     * 安全认证过滤器
     * @return
     */
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setLoginUrl(Global.getContextPath()+Global.getAdminPath()+"/toLogin");
        shiroFilterFactoryBean.setSecurityManager(getSecurityManager());
        shiroFilterFactoryBean.setUnauthorizedUrl("http://www.baidu.com");
        Map<String, Filter> filterMap = new HashMap<>();        
        /*shiro默认是不做任何拦截的 */        

        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        // 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了，我们也可以自己实现
       
/*      filterChainDefinitionMap.put(Global.getContextPath()+Global.getAdminPath()+"/logout", "logout");*/
        
        //单点登录
/*        <entry key="cas" value-ref="casFilter"/>
    	<!-- CAS认证过滤器 -->  
    	<bean id="casFilter" class="org.apache.shiro.cas.CasFilter">  
    		<property name="failureUrl" value="/login"/>
    	</bean>*/
        
        Map<String, String> mapping = new LinkedHashMap<>();
        mapping.put(Global.getContextPath()+"/static/**", "anon");
        mapping.put(Global.getContextPath()+Global.getAdminPath()+"/logout", "logout");
        mapping.put(Global.getContextPath()+Global.getAdminPath()+"/toLogin", "anon");
        mapping.put(Global.getContextPath()+Global.getAdminPath()+"/loginNew", "anon");
        mapping.put(Global.getContextPath()+"/servlet/validateCodeServlet", "anon");//校验码不需要拦截
        mapping.put("/**", "user");//他妈的，这个地方前边加了两个*，他妈的这个地方导致我未登录无法跳转登录界面，直接报验证500错，找了一天
        shiroFilterFactoryBean.setFilterChainDefinitionMap(mapping);
        shiroFilterFactoryBean.setUnauthorizedUrl(Global.getContextPath()+Global.getAdminPath()+"/40333333333333");
        return shiroFilterFactoryBean;
    }
    
    
    
    
    
	@Bean
	public DefaultWebSecurityManager getSecurityManager(){
	DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
	
	SystemAuthorizingRealm systemAuthorizingRealm = new SystemAuthorizingRealm();
	systemAuthorizingRealm.setCredentialsMatcher(new CustomCredentialsMatcher());//自定义密码校验器	
	defaultWebSecurityManager.setRealm(systemAuthorizingRealm);
	defaultWebSecurityManager.setSessionManager(getSessionManager());
	return defaultWebSecurityManager;
	}

	/**
	 * 自定义会话管理配置
	 * @return
	 */
	@Bean
	public SessionManager getSessionManager(){
	SessionManager sessionManager = new SessionManager();
	sessionManager.setSessionDAO(getSessionDAO());
	sessionManager.setGlobalSessionTimeout(1800000);//会话超时时间，单位：毫秒
	sessionManager.setSessionValidationInterval(1800000);//定时清理失效会话, 清理用户直接关闭浏览器造成的孤立会话
	sessionManager.setSessionValidationSchedulerEnabled(true);
	sessionManager.setSessionIdCookie(getSessionIdCookie());
	sessionManager.setSessionIdCookieEnabled(true);
	return sessionManager;
	}
	
	

	@Bean
	public SimpleCookie getSessionIdCookie(){
		org.apache.shiro.web.servlet.SimpleCookie d = new org.apache.shiro.web.servlet.SimpleCookie();
		d.setName("minglead.session.id");
		return d;
	}
	
	
    /**
     * 自定义Session存储容器
     * 如果修改为：JedisSessionDAO 即可支持集群(redis集群)
     * @return
     */
	@Bean
	public SessionDAO getSessionDAO(){
		CacheSessionDAO sessionDAO = new CacheSessionDAO();
		sessionDAO.setSessionIdGenerator(getIdGen());
		sessionDAO.setActiveSessionsCacheName("activeSessionsCache");
		sessionDAO.setCacheManager(getShiroCacheManager());
		return sessionDAO;
	}	
	
	@Bean(name="shiroCacheManager")
	public CacheManager getShiroCacheManager(){
		org.apache.shiro.cache.ehcache.EhCacheManager ehCacheManager = new org.apache.shiro.cache.ehcache.EhCacheManager();
		ehCacheManager.setCacheManagerConfigFile("classpath:cache/ehcache-local.xml");
		return ehCacheManager;
	}
	
	/**
	 * @return
	 */
	@Bean(name="cacheManager")
	public net.sf.ehcache.CacheManager getEhCacheManager(){
		net.sf.ehcache.CacheManager cacheManager = new net.sf.ehcache.CacheManager();
		return cacheManager;
	}

	
	@Bean
	public IdGen getIdGen(){
		com.minglead.springboot.common.utils.IdGen d = new com.minglead.springboot.common.utils.IdGen();
		return d;
	}
	
	@Bean
	public SimpleMappingExceptionResolver initSimpleMappingExceptionResolver(){
		SimpleMappingExceptionResolver config = new SimpleMappingExceptionResolver();
		Properties p = new Properties();
		p.setProperty("org.apache.shiro.authz.UnauthorizedException", "error/403");
		p.setProperty("java.lang.Throwable", "error/500");
		config.setExceptionMappings(p);
		return config;
	}
}